<template>
  <div class="containers main-box">
    <el-button
      type="success"
      size="small"
      icon="el-icon-zoom-in"
      @click="zoomViewport(true)"
    >放大
    </el-button>
    <el-button
      type="warning"
      size="small"
      icon="el-icon-zoom-out"
      @click="zoomViewport(false)"
    >缩小
    </el-button>
    <el-button
      type="info"
      size="small"
      icon="el-icon-rank"
      @click="processReZoom"
    >适中
    </el-button>
    <div v-if="showCol" class="pro-list">
      <ul>
        <li>
          <i class="blue-bg" />
          <span>待办</span>
        </li>
        <li>
          <i class="green-bg" />
          <span>已办</span>
        </li>
        <li>
          <i class="red-bg" />
          <span>退回</span>
        </li>
        <li>
          <i class="orange-bg" />
          <span>撤回</span>
        </li>
        <li>
          <i class="grey-bg" />
          <span>作废</span>
        </li>
      </ul>
    </div>

    <div ref="bpmn-canvas" class="canvas" />
  </div>

</template>

<script>
import { CustomViewer as BpmnViewer } from '@/plugins/package/custom'
import DefaultEmptyXML from '@/plugins/package/designer/plugins/defaultEmpty'
import { isEmpty, isNotEmpty } from '@/utils/index.js'

export default {
  name: 'ViewFind',
  props: {
    xmlData: String,
    activityMap: {
      type: Object,
      default: () => ({})
    }

  },
  data() {
    return {
      dict: {
        type: {
          bpm_task_result: [{
            'label': '暂存',
            'value': 'save'
          },
          {
            'label': '提交',
            'value': 'submit'
          },
          {
            'label': '委派',
            'value': 'delegate'
          },
          {
            'label': '委派完成',
            'value': 'resolve'
          },
          {
            'label': '审批',
            'value': 'approve'
          },
          {
            'label': '已阅',
            'value': 'read'
          },
          {
            'label': '转办',
            'value': 'assign'
          },
          {
            'label': '退回',
            'value': 'back'
          },
          {
            'label': '撤回',
            'value': 'withdraw'
          },
          {
            'label': '终止',
            'value': 'stop'
          }]
        }
      },
      bpmnModeler: null,
      processInstance: undefined,
      prefix: 'flowable',
      showCol: false,
      oldTaskElement: {},
      scElement: null,
      todoId: null,
      startId: null
    }
  },

  watch: {
    xmlData: {
      immediate: true,
      handler(e) {
        if (e) {
          this.$nextTick(() => {
            this.createNewDiagram(e)
          })
        }
      }
    },
    activityMap: {
      immediate: true,
      deep: true,
      handler(e) {
        if (isNotEmpty(e)) {
          this.$nextTick(_ => {
            this.createNewDiagram(this.xmlData)
          })
        }
      }
    }
  },
  mounted() {
    // 初始化
    this.initBpmnModeler()
    this.$once('hook:beforeDestroy', () => {
      console.log('beforeDestroy')
      if (this.bpmnModeler) this.bpmnModeler.destroy()
      // this.$emit("destroy", this.bpmnModeler);
      this.bpmnModeler = null
    })
    // 初始模型的监听器
    this.initModelListeners()
  },

  methods: {
    initBpmnModeler() {
      if (this.bpmnModeler) return
      this.bpmnModeler = new BpmnViewer({
        container: this.$refs['bpmn-canvas'],
        height: 'calc(60vh)',
        bpmnRenderer: {}
      })
    },
    /* 创建新的流程图 */
    createNewDiagram(xml) {
      if (!xml) return
      // 将字符串转换成图显示出来
      const newId = `Process_${new Date().getTime()}`
      const newName = `业务流程_${new Date().getTime()}`
      const xmlString = xml || DefaultEmptyXML(newId, newName, this.prefix)
      try {
        // let { warnings } = await this.bpmnModeler.importXML(xmlString);
        this.bpmnModeler.importXML(xmlString).then(res => {
          // 居中
          // this.fitViewport();
          // 高亮流程图
          this.todoId = null
          this.startId = null
          this.highlightDiagram()
          this.scrollView()
        }).catch((warnings) => {
          if (warnings && warnings.length) {
            warnings.forEach(warn => console.warn(warn))
          }
        })
      } catch (e) {
        console.error(e)
        // console.error(`[Process Designer Warn]: ${e?.message || e}`);
      }
    },
    /* 高亮流程图 */
    highlightDiagram() {
      if (isEmpty(this.activityMap)) {
        return
      }
      this.showCol = true
      //
      // 再次基础上，增加不同审批结果的颜色等等
      const canvas = this.bpmnModeler.get('canvas')
      const _this = this
      try {
        // console.log(this.bpmnModeler.getDefinitions().rootElements[0].flowElements);
        this.bpmnModeler.getDefinitions()?.rootElements[0].flowElements?.forEach(n => {
          const activityList = _this.activityMap[n.id] // 对应的活动列表 每个节点可能经过多次处理
          if (!activityList) return
          const activity = activityList[0] // 找到最近的节点、最近一次的活动
          const completed = _this.isCompleted(n.$type, activityList, activity) // 该节点是否未完成
          // outgoing 出线
          // const outgoing = this.getActivityOutgoing(activity);
          // 开始节点 结束节点
          if (n.$type === 'bpmn:StartEvent' || n.$type === 'bpmn:EndEvent' ||
            n.$type.indexOf('Gateway') > -1) {
            if (!activity) {
              return
            }
            canvas.addMarker(n.id, completed ? 'highlight' : 'highlight-todo')
            if (n.$type === 'bpmn:StartEvent') {
              _this.startId = n.id
            }
          } else if (n.$type === 'bpmn:UserTask' || n.$type === 'bpmn:CallActivity') { // 用户任务
            if (!activity) {
              return
            }
            const cls = this.getActivityMark(n, completed, activity)
            if (cls) {
              canvas.addMarker(n.id, cls)
            }
          }
          // 连线处理
          else if (n.$type === 'bpmn:SequenceFlow') {
            if (!activity) {
              return
            }
            // 连线的目标 是否已完成决定 线的效果
            const targetActivityList = _this.activityMap[n.targetRef.id]// 连线目标节点
            if (!targetActivityList) return
            const targetCompleted = _this.isCompleted(n.targetRef.$type, targetActivityList) // 目标节点是否完成
            canvas.addMarker(n.id, targetCompleted ? 'highlight' : 'highlight-todo')
          }
          // 子流程项
          /* else if (n.$type === 'bpmn:CallActivity') {
                          // 只考虑终止
                          let cls = this.getActivityMark(n.$type, completed, activity);
                          if (cls) {
                            canvas.addMarker(n.id, cls);
                          }
                        }*/
          // 其他的
          else {
            if (!activity) {
              return
            }
            canvas.addMarker(n.id, completed ? 'highlight' : 'highlight-todo')
          }
        })
      } catch (e) {
        console.error(e)
      }
    },
    isCompleted(type, activityList) {
      let todoActivity = null // 该节点未完成的活动
      if (type === 'bpmn:CallActivity') {
        todoActivity = activityList?.find(m => (!m.endTime && m.calledProcessInstanceId)) // 该节点未完成的活动
      } else {
        todoActivity = activityList?.find(m => !m.endTime) // 该节点未完成的活动
      }
      return isEmpty(todoActivity)
    },
    getActivityMark(n, completed, activity) {
      let mark = ''
      if (n.$type === 'bpmn:UserTask') {
        if (completed) {
          if (activity.deleteReason && activity.deleteReason.indexOf('stop') !== -1) {
            mark = 'highlight-cancel'
          } else {
            const comment = activity.commentList ?? [] // 找到活动对应的 taskId
            if (comment && comment.length > 0) {
              mark = this.getResultCss(comment[0].type)
            } else {
              mark = 'highlight'
            }
          }
        } else {
          mark = 'highlight-todo'
        }
      } else if (n.$type === 'bpmn:CallActivity') {
        if (completed) {
          if (activity.deleteReason && activity.deleteReason.indexOf('stop') !== -1) {
            mark = 'highlight-cancel'
          } else {
            mark = 'highlight'
          }
        } else {
          mark = 'highlight-todo'
        }
      } else {
        mark = completed ? 'highlight' : 'highlight-todo'
      }
      if (mark === 'highlight-todo') {
        this.todoId = n.id
      }
      return mark
    },

    getActivityHighlightCss(activity) {
      return activity.endTime ? 'highlight' : 'highlight-todo'
    },
    getResultCss(result) {
      let cls = 'highlight-todo'
      switch (result) {
        case 'assign':
        case 'claim':
          cls = 'highlight-todo'
          break
        case 'submit':
        case 'approve':
        case 'read':
        case 'agree':
        case 'disagree':
          cls = 'highlight'
          break
        case 'back':
          cls = 'highlight-reject'
          break
        case 'withdraw':
          cls = 'highlight-withdraw'
          break
        case 'stop':
          cls = 'highlight-cancel'
          break
        default:
          cls = 'highlight'
          break
      }
      return cls
    },
    getActivityOutgoing(activity) {
      // 如果有 outgoing，则直接使用它
      if (activity.outgoing && activity.outgoing.length > 0) {
        return activity.outgoing
      }
      // 如果没有，则遍历获得起点为它的【bpmn:SequenceFlow】节点们。原因是：bpmn-js 的 UserTask 拿不到 outgoing
      const flowElements = this.bpmnModeler.getDefinitions().rootElements[0].flowElements
      const outgoing = []
      flowElements.forEach(item => {
        if (item.$type !== 'bpmn:SequenceFlow') {
          return
        }
        if (item.sourceRef.id === activity.activityId) {
          outgoing.push(item)
        }
      })
      return outgoing
    },
    initModelListeners() {
      const EventBus = this.bpmnModeler.get('eventBus')
      const that = this
      // 注册需要的监听事件
      EventBus.on('element.hover', function(eventObj) {
        const element = eventObj ? eventObj.element : null
        // if (element.type === 'bpmn:UserTask') {
        that.elementHover(element)
        // }
      })
      /* EventBus.on('element.out', function(eventObj) {
        let element = eventObj ? eventObj.element : null;
        if (element.type === 'bpmn:UserTask') {
          that.elementOut(element);
        }
      });*/
      EventBus.on('element.click', function(eventObj) {
        const element = eventObj ? eventObj.element : null
        if (element.type !== 'bpmn:UserTask' && that.oldTaskElement.id) {
          that.elementOut(that.oldTaskElement)
        }
      })
    },
    // 流程图的元素被 hover
    elementHover(element) {
      this.element = element
      !this.elementOverlayIds && (this.elementOverlayIds = {})
      !this.overlays && (this.overlays = this.bpmnModeler.get('overlays'))
      // 展示信息
      if (!this.elementOverlayIds[element.id] && element.type !== 'bpmn:Process') {
        const activityList = this.activityMap[element.id] // 对应的活动列表 每个节点可能经过多次处理
        if (!activityList) return

        let html = `` // 默认值
        if (element.type === 'bpmn:StartEvent') {
          /* html = `<p>发起人：${this.processInstance.userName}</p>
                  <p>部门：${this.processInstance.deptName}</p>
                  <p>创建时间：${this.parseTime(this.processInstance.createTime)}`;*/
        }
        // 用户任务
        else if (element.type === 'bpmn:UserTask') {
          html = this.getTaskActivityHtml(activityList)
        } else if (element.type === 'bpmn:CallActivity') {
          html = this.getCallActivityHtml(activityList)
        } else if (element.type === 'bpmn:EndEvent') {
          /* html = `<p>结果：${'22'}</p>`;
          if (this.processInstance.endTime) {
            html += `<p>结束时间：${this.parseTime(this.processInstance.endTime)}</p>`
          }*/
        }

        if (html) {
          // 先清掉原来的
          if (this.oldTaskElement.id) {
            this.elementOut(this.oldTaskElement)
          }
          this.elementOverlayIds[element.id] = this.overlays.add(element, {
            position: { left: 0, bottom: 0 },
            html: `<div class="log-element-overlays" id="logDiv" ">${html}</div>`
          })
          this.oldTaskElement = element
        }
      }
    },
    getTaskActivityHtml(activityList) {
      let html = `<table class="table-cls"  >
                    <tr class="title-cl">
                        <th>序号</th>
                        <th>审批人</th>
                        <th>处理方式</th>
                        <th>处理意见</th>
                        <th>到达时间</th>
                        <th>结束时间</th>
                    </tr>`
      // let num = activityList.length ;
      let num = 1
      for (let i = activityList.length - 1; i >= 0; i--) {
        const activity = activityList[i]
        const completed = isNotEmpty(activity.endTime)
        const comments = activity.commentList ?? [] // 活动审批意见
        html += `<tr>
                  <td>${num}</tdclasstable-cls-td>
                  <td>${activity.assigneeName}</td>
                  <td>${this.getActivityResult(comments, completed, activity.deleteReason)}</td>
                  <td>` + this.getActivityComment(comments, activity.deleteReason) + `</td>
                  <td>${this.parseTime(activity.startTime)}</td>
                  <td>${this.parseTime(activity.endTime)}</td>
                  </tr>`

        num++
      }
      html += `</table>`
      return html
    },
    parseTime(date) {
      if (isEmpty(date)) {
        return null
      }
      try {
        return new Date(date).toLocaleString()
      } catch (e) {
        return null
      }
    },
    selectDictLabel(datas, value) {
      if (value === undefined) {
        return ''
      }
      var actions = []
      Object.keys(datas).some((key) => {
        if (datas[key].value == ('' + value)) {
          actions.push(datas[key].label)
          return true
        }
      })
      if (actions.length === 0) {
        actions.push(value)
      }
      return actions.join('')
    },
    getCallActivityHtml(activityList) {
      let html = `<table class="table-cls"  >
                    <tr class="title-cl">
                        <th>序号</th>
                        <th>子流程名称</th>
                        <th>当前处理人</th>
                        <th>启动时间</th>
                        <th>结束时间</th>
                    </tr>`
      let num = 1
      for (let i = activityList.length - 1; i >= 0; i--) {
        const activity = activityList[i]
        if (isEmpty(activity.calledProcessInstanceId)) {
          continue
        }
        let assigneeName = isEmpty(activity.endTime) ? activity.assigneeName : '已完成'
        if (assigneeName === null || assigneeName === 'null') {
          assigneeName = ''
        }
        html += `<tr>
                    <td>${num}</td>
                    <td>${activity.calledProcessInstanceName}</td>
                    <td>${assigneeName}</td>
                    <td>${this.parseTime(activity.startTime)}</td>
                    <td>${this.parseTime(activity.endTime)}</td>
                    </tr>`

        num++
      }
      html += `</table>`
      return html
    },
    getActivityResult(comments, completed, deleteReason) {
      let result = ''
      if (!completed) {
        result = '处理中...'
      } else {
        if (deleteReason && deleteReason.indexOf('stop') !== -1) {
          result = this.selectDictLabel(this.dict.type.bpm_task_result, 'stop')
        } else {
          if (comments && comments.length > 0) {
            result = this.selectDictLabel(this.dict.type.bpm_task_result, comments[0].type)
          }
        }
      }

      return result
    },
    getActivityComment(comments, deleteReason) {
      let html = ``
      if (deleteReason && deleteReason && deleteReason.indexOf('stop') !== -1) {
        const array = deleteReason.split('_|_')
        html += `<p style="margin:0;">${array[array.length - 1]}</p>`
      } else {
        if (comments && comments.length > 0) {
          if (comments.length === 1) {
            html += `<p style="margin:0;">${comments[0].fullMessage}</p>`
          } else {
            let num = 1
            for (let i = comments.length - 1; i >= 0; i--) {
              html += `<p style="margin:0;">${num}、${comments[i].fullMessage}</p>`
              num++
            }
          }
        }
      }

      return html
    },

    // 流程图的元素被 out
    elementOut(element) {
      try {
        this.overlays?.remove({ element })
        if (this.elementOverlayIds) {
          this.elementOverlayIds[element.id] = null
        }
      } catch (e) {
        console.error(e)
      }
    },
    scrollView() {
      const canvas = this.bpmnModeler.get('canvas')
      const elementRegistry = this.bpmnModeler.get('elementRegistry')
      const viewBox = canvas.viewbox()
      if (this.todoId) {
        const el = elementRegistry.get(this.todoId)
        if (el) {
          // 减去 20 的默认画布内边距
          const vPadding = Math.floor((viewBox.outer.height - el.height) / 2) - 20
          const hPadding = Math.floor((viewBox.outer.width - el.width) / 2) - 20
          // const padding = Math.floor(Math.min(vPadding, hPadding));

          canvas.scrollToElement(el, { top: vPadding, bottom: vPadding, left: hPadding, right: hPadding })
        }
      } else if (this.startId) {
        const el = elementRegistry.get(this.startId)
        if (el) {
          // 减去 20 的默认画布内边距
          const hPadding = Math.floor((viewBox.outer.width - el.width) / 2) - 20
          canvas.scrollToElement(el, { top: 0, bottom: viewBox.outer.height, left: hPadding, right: hPadding })
        }
      }
    },
    // 让图能自适应屏幕
    fitViewport() {
      this.zoom = this.bpmnModeler.get('canvas').zoom('fit-viewport', 'auto')
      this.bpmnModeler.get('canvas').zoom(0.8)
    },
    processReZoom() {
      this.zoom = this.bpmnModeler.get('canvas').zoom('fit-viewport', 'auto')
    },
    // 放大缩小
    zoomViewport(zoomIn = true) {
      this.zoom = this.bpmnModeler.get('canvas').zoom()
      this.zoom += (zoomIn ? 0.1 : -0.1)
      if (this.zoom >= 0.2) this.bpmnModeler.get('canvas').zoom(this.zoom)
    }

  }

}
</script>

<style>

.pro-list {
  width: 40%;
  overflow: hidden;
  float: right;
  margin-top: -10px;
  margin-right: 25%;
}

.pro-list ul li {
  float: left;
  margin-right: 15px;
  line-height: 30px;
  height: 30px;
  overflow: hidden;
}

.pro-list ul li span {
  float: left;
  margin-left: 5px;
}

.pro-list ul li i {
  padding: 8px;
  float: left;
  margin-top: 6px;
}

.blue-bg {
  background: rgba(24, 144, 255, 0.2);
  border: 1px dashed #1890ff;
  border-radius: 4px;
}

.red-bg {
  background: rgba(255, 0, 0, 0.4);
  border-radius: 4px;
}

.green-bg {
  background: rgba(0, 128, 0, 0.4);
  border-radius: 4px;
}

.orange-bg {
  background: rgba(255, 165, 0, 0.4);
  border-radius: 4px;
}

.grey-bg {
  background: grey;
  border-radius: 4px;
}

/** 审批记录table */
table.table-cls tr td, table.table-cls tr th {
  border: 1px solid #dadfe3;
  text-align: center;
  height: 40px;
  line-height: 40px;
}

table.table-cls tr td {
  border: 1px solid #dadfe3;
  text-align: center;
  height: 32px;
  line-height: 32px;
}

.table-cls {
  border-collapse: collapse;
  width: 100%;
}

.bjs-powered-by {
  display: none;
}

@keyframes marchingants {
  to {
    stroke-dashoffset: 19;
  }
}

/** 处理中 */
.highlight-todo.djs-connection > .djs-visual > path {
  stroke: #1890ff !important;
  stroke-dasharray: 4px !important;
  fill-opacity: 0.2 !important;
}

.highlight-todo.djs-shape .djs-visual > :nth-child(1) {
  fill: #1890ff !important;
  stroke: #1890ff !important;
  stroke-dasharray: 5px !important;
  fill-opacity: 0.2 !important;
  animation: marchingants 1s forwards infinite linear;
}

/deep/ .highlight-todo.djs-connection > .djs-visual > path {
  stroke: #1890ff !important;
  stroke-dasharray: 4px !important;
  fill-opacity: 0.2 !important;
  marker-end: url(#sequenceflow-end-_E7DFDF-_E7DFDF-803g1kf6zwzmcig1y2ulm5egr);
}

/deep/ .highlight-todo.djs-shape .djs-visual > :nth-child(1) {
  fill: #1890ff !important;
  stroke: #1890ff !important;
  stroke-dasharray: 4px !important;
  fill-opacity: 0.2 !important;
}

/** 通过 */
.highlight.djs-shape .djs-visual > :nth-child(1) {
  fill: green !important;
  stroke: green !important;
  fill-opacity: 0.2 !important;
}

.highlight.djs-shape .djs-visual > :nth-child(2) {
  fill: green !important;
}

.highlight.djs-shape .djs-visual > circle {
  fill: green !important;
  stroke: green !important;
  fill-opacity: 0.2 !important;
}

.highlight.djs-shape .djs-visual > path {
  fill: green !important;
  fill-opacity: 0.2 !important;
  stroke: green !important;
}

.highlight.djs-connection > .djs-visual > path {
  stroke: green !important;
}

.highlight:not(.djs-connection) .djs-visual > :nth-child(1) {
  fill: green !important; /* color elements as green */
}

/deep/ .highlight.djs-shape .djs-visual > :nth-child(1) {
  fill: green !important;
  stroke: green !important;
  fill-opacity: 0.2 !important;
}

/deep/ .highlight.djs-shape .djs-visual > :nth-child(2) {
  fill: green !important;
}

/deep/ .highlight.djs-shape .djs-visual > path {
  fill: green !important;
  fill-opacity: 0.2 !important;
  stroke: green !important;
}

/deep/ .highlight.djs-connection > .djs-visual > path {
  stroke: green !important;
}

/** 退回 */
.highlight-reject.djs-shape .djs-visual > :nth-child(1) {
  fill: red !important;
  stroke: red !important;
  fill-opacity: 0.2 !important;
}

.highlight-reject.djs-shape .djs-visual > :nth-child(2) {
  fill: red !important;
}

.highlight-reject.djs-shape .djs-visual > circle {
  fill: red !important;
  stroke: red !important;
  fill-opacity: 0.2 !important;
}

.highlight-reject.djs-shape .djs-visual > path {
  fill: red !important;
  fill-opacity: 0.2 !important;
  stroke: red !important;
}

.highlight-reject.djs-connection > .djs-visual > path {
  stroke: red !important;
}

.highlight-reject:not(.djs-connection) .djs-visual > :nth-child(1) {
  fill: red !important; /* color elements as green */
}

/deep/ .highlight-reject.djs-shape .djs-visual > :nth-child(1) {
  fill: red !important;
  stroke: red !important;
  fill-opacity: 0.2 !important;
}

/deep/ .highlight-reject.djs-shape .djs-visual > :nth-child(2) {
  fill: red !important;
}

/deep/ .highlight-reject.djs-shape .djs-visual > path {
  fill: red !important;
  fill-opacity: 0.2 !important;
  stroke: red !important;
}

/deep/ .highlight-reject.djs-connection > .djs-visual > path {
  stroke: red !important;
}

/** 撤回 */
.highlight-withdraw.djs-shape .djs-visual > :nth-child(1) {
  fill: orange !important;
  stroke: orange !important;
  fill-opacity: 0.2 !important;
}

.highlight-withdraw.djs-shape .djs-visual > :nth-child(2) {
  fill: orange !important;
}

.highlight-withdraw.djs-shape .djs-visual > circle {
  fill: orange !important;
  stroke: orange !important;
  fill-opacity: 0.2 !important;
}

.highlight-withdraw.djs-shape .djs-visual > path {
  fill: orange !important;
  fill-opacity: 0.2 !important;
  stroke: orange !important;
}

.highlight-withdraw.djs-connection > .djs-visual > path {
  stroke: orange !important;
}

.highlight-withdraw:not(.djs-connection) .djs-visual > :nth-child(1) {
  fill: orange !important; /* color elements as green */
}

/deep/ .highlight-withdraw.djs-shape .djs-visual > :nth-child(1) {
  fill: orange !important;
  stroke: orange !important;
  fill-opacity: 0.2 !important;
}

/deep/ .highlight-withdraw.djs-shape .djs-visual > :nth-child(2) {
  fill: orange !important;
}

/deep/ .highlight-withdraw.djs-shape .djs-visual > path {
  fill: orange !important;
  fill-opacity: 0.2 !important;
  stroke: orange !important;
}

/deep/ .highlight-withdraw.djs-connection > .djs-visual > path {
  stroke: orange !important;
}

/** 已取消 */
.highlight-cancel.djs-shape .djs-visual > :nth-child(1) {
  fill: grey !important;
  stroke: grey !important;
  fill-opacity: 0.2 !important;
}

.highlight-cancel.djs-shape .djs-visual > :nth-child(2) {
  fill: grey !important;
}

.highlight-withdraw.djs-shape .djs-visual > circle {
  fill: grey !important;
  stroke: grey !important;
  fill-opacity: 0.2 !important;
}

.highlight-cancel.djs-shape .djs-visual > path {
  fill: grey !important;
  fill-opacity: 0.2 !important;
  stroke: grey !important;
}

.highlight-cancel.djs-connection > .djs-visual > path {
  stroke: grey !important;
}

.highlight-cancel:not(.djs-connection) .djs-visual > :nth-child(1) {
  fill: grey !important; /* color elements as green */
}

/deep/ .highlight-cancel.djs-shape .djs-visual > :nth-child(1) {
  fill: grey !important;
  stroke: grey !important;
  fill-opacity: 0.2 !important;
}

/deep/ .highlight-cancel.djs-shape .djs-visual > :nth-child(2) {
  fill: grey !important;
}

/deep/ .highlight-cancel.djs-shape .djs-visual > path {
  fill: grey !important;
  fill-opacity: 0.2 !important;
  stroke: grey !important;
}

/deep/ .highlight-cancel.djs-connection > .djs-visual > path {
  stroke: grey !important;
}

.log-element-overlays {
  box-sizing: border-box;
  padding: 0px;
  background: #ffffff;
  /*border-radius: 4px;*/
  color: #23272a;
  width: 700px;
  max-height: 300px;
  overflow: auto;
  position: absolute;
  left: -250px;
}

.title-cl {
  background-color: #004a83;
  color: #ffffff;
}
</style>
